/*
* The MIT License
*
* Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package hudson.tasks;
import hudson.model.FreeStyleBuild;
import hudson.model.FreeStyleProject;
import hudson.model.User;
import hudson.tasks.Mailer.DescriptorImpl;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.Bug;
import org.jvnet.hudson.test.FailureBuilder;
import org.jvnet.hudson.test.Email;
import org.jvnet.hudson.test.FakeChangeLogSCM;
import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.JenkinsRule.WebClient;
import org.jvnet.hudson.test.UnstableBuilder;
import org.jvnet.mock_javamail.Mailbox;
import javax.mail.Address;
import javax.mail.internet.InternetAddress;
import jenkins.model.JenkinsLocationConfiguration;
import java.util.concurrent.atomic.AtomicLong;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.hamcrest.Matchers.containsString;
/**
* @author Kohsuke Kawaguchi
*/
public class MailerTest {
/** Default recipient used in tests. */
private static final String RECIPIENT = "you <you@sun.com>";
/** Fixed FAILURE builder. */
private static final Builder FAILURE = new FailureBuilder();
/** Fixed UNSTABLE builder. */
private static final Builder UNSTABLE = new UnstableBuilder();
/** Commit author 1. */
private static final String AUTHOR1 = "author1@example.com";
/** Commit author 2. */
private static final String AUTHOR2 = "author2@example.com";
/** Change counter. */
private static final AtomicLong COUNTER = new AtomicLong(0L);
@Rule
public JenkinsRule rule = new JenkinsRule();
private static Mailbox getMailbox(String recipient) throws Exception {
return Mailbox.get(new InternetAddress(recipient));
}
private static Mailbox getEmptyMailbox(String recipient) throws Exception {
Mailbox inbox = getMailbox(recipient);
inbox.clear();
return inbox;
}
private TestProject create(boolean notifyEveryUnstableBuild, boolean sendToIndividuals) throws Exception {
Mailer m = new Mailer(RECIPIENT, notifyEveryUnstableBuild, sendToIndividuals);
return new TestProject(m);
}
@Bug(1566)
@Test
public void testSenderAddress() throws Exception {
// intentionally give the whole thin in a double quote
JenkinsLocationConfiguration.get().setAdminAddress("\"me <me@sun.com>\"");
// create a project to simulate a build failure
TestProject project = create(false, false).failure().buildAndCheck(1);
// build it and check sender address
Mailbox yourInbox = getMailbox(RECIPIENT);
Address[] senders = yourInbox.get(0).getFrom();
assertEquals(1,senders.length);
assertEquals("me <me@sun.com>",senders[0].toString());
}
@Email("http://www.nabble.com/email-recipients-disappear-from-freestyle-job-config-on-save-to25479293.html")
@Test
public void testConfigRoundtrip() throws Exception {
Mailer m = new Mailer("kk@kohsuke.org", false, true);
verifyRoundtrip(m);
m = new Mailer("", true, false);
verifyRoundtrip(m);
}
private void verifyRoundtrip(Mailer before) throws Exception {
FreeStyleProject p = rule.createFreeStyleProject();
p.getPublishersList().add(before);
rule.submit(rule.createWebClient().getPage(p,"configure").getFormByName("config"));
Mailer after = p.getPublishersList().get(Mailer.class);
assertNotSame(before,after);
rule.assertEqualBeans(before,after,"recipients,dontNotifyEveryUnstableBuild,sendToIndividuals");
}
@Test
public void testGlobalConfigRoundtrip() throws Exception {
DescriptorImpl d = Mailer.descriptor();
JenkinsLocationConfiguration.get().setAdminAddress("admin@me");
d.setDefaultSuffix("default-suffix");
d.setHudsonUrl("http://nowhere/");
d.setSmtpHost("smtp.host");
d.setSmtpPort("1025");
d.setUseSsl(true);
d.setSmtpAuth("user","pass");
rule.submit(rule.createWebClient().goTo("configure").getFormByName("config"));
assertEquals("admin@me", JenkinsLocationConfiguration.get().getAdminAddress());
assertEquals("default-suffix",d.getDefaultSuffix());
assertEquals("http://nowhere/",d.getUrl());
assertEquals("smtp.host",d.getSmtpServer());
assertEquals("1025",d.getSmtpPort());
assertEquals(true,d.getUseSsl());
assertEquals("user",d.getSmtpAuthUserName());
assertEquals("pass",d.getSmtpAuthPassword());
d.setUseSsl(false);
d.setSmtpAuth(null,null);
rule.submit(rule.createWebClient().goTo("configure").getFormByName("config"));
assertEquals(false,d.getUseSsl());
assertNull("expected null, got: " + d.getSmtpAuthUserName(), d.getSmtpAuthUserName());
assertNull("expected null, got: " + d.getSmtpAuthPassword(), d.getSmtpAuthPassword());
}
/**
* Simulates {@link JenkinsLocationConfiguration} is not configured.
*/
private static class CleanJenkinsLocationConfiguration extends JenkinsLocationConfiguration {
@Override
public synchronized void load() {
getConfigFile().delete();
super.load();
}
};
/**
* Test {@link JenkinsLocationConfiguration} can load hudsonUrl.
*/
@Test
public void testHudsonUrlCompatibility() throws Exception {
// not configured.
assertNull(new CleanJenkinsLocationConfiguration().getUrl());
Mailer m = new Mailer("", true, false);
FreeStyleProject p = rule.createFreeStyleProject();
p.getPublishersList().add(m);
WebClient wc = rule.createWebClient();
rule.submit(wc.getPage(p,"configure").getFormByName("config"));
// configured via the marshaled XML file of Mailer
assertEquals(wc.getContextPath(), new CleanJenkinsLocationConfiguration().getUrl());
}
@Test
public void testNotifyEveryUnstableBuild() throws Exception {
create(true, false).failure()
.buildAndCheck(1)
.buildAndCheck(1)
.unstable()
.buildAndCheck(1)
.buildAndCheck(1)
.success()
.buildAndCheck(1) /* back to normal mail. */
.buildAndCheck(0)
.unstable()
.buildAndCheck(1)
.failure()
.buildAndCheck(1);
}
@Test
public void testNotNotifyEveryUnstableBuild() throws Exception {
create(false, false)
.buildAndCheck(0)
.buildAndCheck(0)
.unstable()
.buildAndCheck(1)
.buildAndCheck(0)
.success()
.buildAndCheck(1) /* back to normal mail. */
.buildAndCheck(0)
.unstable()
.buildAndCheck(1)
.buildAndCheck(0)
.failure()
.buildAndCheck(1)
.buildAndCheck(1);
}
@SuppressWarnings("deprecation")
@Test
public void testNotifyCulprits() throws Exception {
MailSender.debug = true;
try {
rule.jenkins.setSecurityRealm(rule.createDummySecurityRealm());
User.get("author1").addProperty(new Mailer.UserProperty(AUTHOR1));
User.get("author2").addProperty(new Mailer.UserProperty(AUTHOR2));
TestProject project = create(true, true).buildAndCheck(0);
// Changes with no problems
project.commit("author1").clearBuild().check(0, 0, 0);
// Commit causes build to be unstable
project.commit("author1").unstable().clearBuild().check(1, 1, 0);
// Another one
project.commit("author2").clearBuild().check(1, 1, 1);
// Back to normal
project.commit("author1").success().clearBuild().check(1, 1, 1);
// Now a failure
project.commit("author2").failure().clearBuild().check(1, 0, 1);
} finally {
MailSender.debug = false;
}
}
@Issue("JENKINS-40224")
@Test
public void testMessageText() throws Exception {
create(true, false)
.failure()
.buildAndCheckContent()
.unstable()
.buildAndCheckContent()
.success()
.buildAndCheckContent();
}
private final class TestProject {
private final FakeChangeLogSCM scm = new FakeChangeLogSCM();
private final FreeStyleProject project;
TestProject(Mailer m) throws Exception {
project = rule.createFreeStyleProject();
project.setScm(scm);
project.getPublishersList().add(m);
}
TestProject changeStatus(Builder status) {
project.getBuildersList().clear();
if (status != null) {
project.getBuildersList().add(status);
}
return this;
}
TestProject success() {
return changeStatus(null);
}
TestProject failure() {
return changeStatus(FAILURE);
}
TestProject unstable() {
return changeStatus(UNSTABLE);
}
TestProject commit(String author) {
scm.addChange().withAuthor(author).withMsg("commit #" + COUNTER.incrementAndGet());
return this;
}
TestBuild build(String... mailboxesToClear) throws Exception {
for (String recipient : mailboxesToClear) {
getEmptyMailbox(recipient);
}
return new TestBuild(project.scheduleBuild2(0).get());
}
TestBuild clearBuild() throws Exception {
return build(RECIPIENT, AUTHOR1, AUTHOR2);
}
TestProject buildAndCheck(int expectedSize, String recipient) throws Exception {
build(recipient).check(expectedSize, recipient);
return this;
}
TestProject buildAndCheck(int expectedSize) throws Exception {
return buildAndCheck(expectedSize, RECIPIENT);
}
TestProject buildAndCheckContent() throws Exception {
build(RECIPIENT).checkContent();
return this;
}
}
private final class TestBuild {
private final FreeStyleBuild build;
private final String log;
TestBuild(FreeStyleBuild build) throws Exception {
this.build = build;
this.log = rule.getLog(build);
}
TestBuild check(int expectedSize, String recipient) throws Exception {
final Mailbox inbox = getMailbox(recipient);
assertEquals(log, expectedSize, inbox.size());
return this;
}
TestBuild check(int expectedRecipient, int expectedAuthor1, int expectedAuthor2) throws Exception {
return check(expectedRecipient, RECIPIENT).check(expectedAuthor1, AUTHOR1).check(expectedAuthor2, AUTHOR2);
}
void checkContent() throws Exception {
String expectedInMessage = String.format("<%sjob/%s/%d/display/redirect>\n\n", rule.getURL(), this.build.getProject().getName(), this.build.getNumber());
String emailContent = getMailbox(RECIPIENT).get(0).getContent().toString();
assertThat(emailContent, containsString(expectedInMessage));
}
}
}